import UIKit

var str = "Hello, playground"

//1 实例方法（Instance Methods）
//实例方法是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能，并以此来支撑实例的功能。实例方法的语法与函数完全一致，详情参见 函数。

//实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用
class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    //方法的参数可以有一个外部名称:在外部调用时使用,和一个据局部名称,在方法内部使用
    func increment(by amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

//和调用属性一样，用点语法（dot syntax）调用实例方法：
let counter = Counter()
counter.increment()
counter.increment(by: 5)
counter.reset()

//2 self 属性
//类型的每一个实例都有一个隐含属性叫做 self，self 完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的 self 属性来引用当前实例。
//实际上，你不必在你的代码里面经常写 self。不论何时，只要在一个方法中使用一个已知的属性或者方法名称，如果你没有明确地写 self，Swift 假定你是指当前实例的属性或者方法。

//使用这条规则的主要场景是实例方法的某个参数名称与实例的某个属性名称相同的时候。在这种情况下，参数名称享有优先权，并且在引用属性时必须使用一种更严格的方式。这时你可以使用 self 属性来区分参数名称和属性名称。


//3 在实例方法中修改值类型
//结构体和枚举是值类型。默认情况下，值类型的属性不能在它的实例方法中被修改。
//
//但是，如果你确实需要在某个特定的方法中修改结构体或者枚举的属性，你可以为这个方法选择 可变（mutating）行为，然后就可以从其方法内部改变它的属性；并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的 self 属性赋予一个全新的实例，这个新实例在方法结束时会替换现存实例。
//
//要使用 可变方法，将关键字 mutating 放到方法的 func 关键字之前就可以了：
struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at(\(somePoint.x),\(somePoint.y))")

//注意，不能在结构体类型的常量（a constant of structure type）上调用可变方法，因为其属性不能被改变，即使属性是变量属性，详情参见 常量结构体的存储属性：

//4 在可变方法中给 self 赋值
//可变方法能够赋给隐含属性 self 一个全新的实例。上面 Point 的例子可以用下面的方式改写：

struct Point1 {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double,y deltaY:Double) {
        self = Point1(x: x + deltaX, y: y + deltaY)
    }
}

//枚举的可变方法可以把 self 设置为同一枚举类型中不同的成员：
enum TristateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}
var ovenLight = TristateSwitch.low
ovenLight.next()
print("\(ovenLight)")
ovenLight.next()
print("\(ovenLight)")

//5 类方法
//在方法的 func 关键字之前加上关键字 static
//类还可以用关键字 class 来指定，从而允许子类重写父类该方法的实现。
class SomeClass {
    class func someTypeMethod() {
        //在这里实现类型方法
        print("类中的类方法")
    }
}
SomeClass.someTypeMethod()
//在类型方法的方法体（body）中，self 属性指向这个类型本身，而不是类型的某个实例。这意味着你可以用 self 来消除类型属性和类型方法参数之间的歧义
